// Partial 将属性变为可选
interface Data {
    code: number,
    data: any,
    msg: string
}
type NewData = Partial<Data>

let obj: NewData = {
    code: 0
}

// Required 反向Partial
type RequiredData = Required<NewData>
let obj2: RequiredData = {
    code: 2,
    data: [],
    msg: '22'
}

// Readonly 只读属性
type ReadonlyData = Readonly<Data>
let a: ReadonlyData = {
    code: 1,
    msg: 'ss',
    data: []
}

// a.code = 2 // err 无法分配到 "code" ，因为它是只读属性

// Pick 挑选

type PickData = Pick<Data, 'code' | 'msg'>

let obj3: PickData = {
    code: 0,
    msg: '22'
}

// Record 键值映射
type Keys = 'dog' | 'cat' 
type RecordData = Record<Keys, Data>

let obj4: RecordData = {
    dog: {
        code: 0,
        msg: 'xx',
        data: []
    },
    cat: {
        code: 1,
        msg: 'zz',
        data: []
    }
}

// Exclude <=> Extract
// type Exclude<T, U> = T extends U ? never : T;
// type Extract<T, U> = T extends U ? T : never;

type ExcludeData = Exclude<Date, object> // never
// type ExcludeData = Exclude<'code', Data> // code
// type ExcludeData = Exclude<keyof Data, string> // never
// let obj5: ExcludeData = (() => {
//     throw new Error('new err')
// })();

type ExcludeData2 = Exclude<Data, Function>

let obj6: ExcludeData2 = {
    code: 0,
    msg: '22',
    data: []
}

// Omit 忽略
// type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;

type OmitData = Omit<Data, 'code'>

// extends keyof xxx
// function fn<T extends keyof Data>(params: T) {
//     console.log(params);
// }
// fn(1)

let obj7: OmitData = {
    msg: 'xx',
    data: []
}

// NonNullable
// type NonNullable<T> = T extends null | undefined ? never : T;

// let a
// type NonNullableA = NonNullable<typeof a>

// Parameters 获取函数中的参数
// type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;

type Func = (user: number) => number;
type Func2 = () => number;

type Params = Parameters<Func>
type Params2 = Parameters<Func2>

let obj8: Params = [1]
let obj9: Params2 = []


// ConstructorParameters 获取类中的参数
// type ConstructorParameters<T extends new (...args: any) => any> = T extends new (...args: infer P) => any ? P : never;

class Point {
    public name: string
    constructor(name: string, age: number) {
        this.name = name
    }
}

type ConstructorParametersData = ConstructorParameters<typeof Point>
let obj10: ConstructorParametersData = ['22', 11]

function init(...rest: ConstructorParametersData): ConstructorParametersData {
    const a = rest[0]
    const b = rest[1]
    return [a, b]
}

const init1 = init('22', 11)


// ReturnType 推断返回值的类型
// type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;

type Res = (name: string) => Promise<Data>

type ReturnTypeData = ReturnType<Func>
type ReturnTypeData2 = ReturnType<Res>

let obj11: ReturnTypeData2 = Promise.resolve({
    data: [],
    code: 1,
    msg: 'xx'
})

// InstanceType
type InstanceTypeData = InstanceType<typeof Point>
let obj12 = new Point('agou', 11)

type ReturnTypeDate = ReturnType<typeof Object.keys>
